#pragma once

#include <iostream>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"

namespace ns_client
{
  const static uint16_t default_port = 8080; // 默认端口号

  class UdpClient
  {
  public:
    UdpClient(const std::string &ip, uint16_t port = default_port)
        : ip_(ip), port_(port)
    {
      std::cerr << ip << " : " << port << std::endl;
    }

    void InitClient()
    {
      // 创建套接字
      sock_ = socket(AF_INET, SOCK_DGRAM, 0);
      if (sock_ == -1)
      {
        std::cerr << "Create Socket Fail: " << strerror(errno) << std::endl;
        exit(SOCKET_ERR);
      }
      std::cout << "Create Socket Succese: " << sock_ << std::endl;

      svr_.sin_family = AF_INET;
      svr_.sin_port = htons(port_);
      svr_.sin_addr.s_addr = inet_addr(ip_.c_str());

      // 需要绑定，但不由我们手动绑定
      // OS TODO
    }

    void StartClient()
    {
      char buffer[1024] = {0};
      while (true)
      {
        // 发信息
        std::string msg;
        std::cout << "Please Enter >>";
        std::getline(std::cin, msg);

        socklen_t len = sizeof svr_;
        sendto(sock_, msg.c_str(), msg.size(), 0, (struct sockaddr *)&svr_, len);

        // 收信息
        int n = recvfrom(sock_, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&svr_, &len);
        if(n > 0) buffer[n] = '\0';
        else continue;

        // 提取服务端的信息
        std::string serverip = inet_ntoa(svr_.sin_addr); // ip
        uint16_t serverport = ntohs(svr_.sin_port);      // port
        std::cout << "server [" << serverip << ":" << serverport << "] # " << buffer << std::endl;
      }
    }

    ~UdpClient()
    {
    }

  private:
    int sock_;        // 套接字
    std::string ip_;  // IP地址
    uint16_t port_;   // 端口
    sockaddr_in svr_; // 服务端信息
  };
}
